﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sgr;
using Sgr.AspNetCore.ActionFilters.AuditLogs;
using Sgr.AspNetCore.Middlewares.AuditLogs;
using Sgr.AspNetCore.Middlewares.ExceptionHandling;
using Sgr.Modules;
using System;
using System.Linq;

namespace Microsoft.AspNetCore.Builder
{
    /// <summary>
    /// 扩展
    /// </summary>
    public static class ApplicationBuilderExtensions
    {
        private const string RateLimiterMiddlewareKey = "Sgr.RateLimiterMiddlewareRegistered";

        /// <summary>
        /// 开启限流中间件
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IApplicationBuilder UseRateLimiterOnce(this IApplicationBuilder app)
        {
            Check.NotNull(app, nameof(app));

            // 检查是否已注册
            if (!app.Properties.ContainsKey(RateLimiterMiddlewareKey))
            {
                app.UseRateLimiter();
                app.Properties[RateLimiterMiddlewareKey] = true;
            }

            return app;
        }

        /// <summary>
        /// 配置模块中间件
        /// </summary>
        public static IApplicationBuilder ConfigureSgrModuleMiddlewares(this IApplicationBuilder app)
        {
            var modules = app.ApplicationServices.GetServices<IModuleStartup>().OrderBy(f => f.Order);
            var webHostEnvironment = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();

            foreach (var module in modules)
            {
                module.Configure(app, webHostEnvironment);
            }

            return app;
        }

        /// <summary>
        /// 配置模块终结点
        /// </summary>
        public static IEndpointRouteBuilder MapSgrModuleEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
        {
            var modules = endpointRouteBuilder.ServiceProvider.GetServices<IModuleStartup>().OrderBy(f => f.Order);

            foreach (var module in modules)
            {
                module.ConfigureEndpoints(endpointRouteBuilder);
            }

            return endpointRouteBuilder;
        }

        /// <summary>
        /// 开启自定义异常处理中间件
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseSgrExceptionHandler(this IApplicationBuilder app, Action<IExceptionHandlingOptions>? configure = null)
        {
            var exceptionHandlingOptions = app.ApplicationServices.GetRequiredService<IExceptionHandlingOptions>();
            configure?.Invoke(exceptionHandlingOptions);

            app.UseMiddleware<ExceptionHandlingMiddleware>();

            return app;
        }

        /// <summary>
        /// 开启审计日志中间件
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseSgrAuditLog(this IApplicationBuilder app, Action<IAuditLogMiddlewareOptions>? configure = null)
        {
            var middlewareOptions = app.ApplicationServices.GetRequiredService<IAuditLogMiddlewareOptions>();
            configure?.Invoke(middlewareOptions);

            app.UseMiddleware<AuditLogMiddleware>();

            return app;
        }

        /// <summary>
        /// 开启审计日志拦截器
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseSgrAuditLogFilters(this IApplicationBuilder app, Action<IAuditLogFilterOptions>? configure = null)
        {
            var auditLogFilterOptions = app.ApplicationServices.GetRequiredService<IAuditLogFilterOptions>();
            configure?.Invoke(auditLogFilterOptions);

            //解决在审计日志中读取读取HttpBody的问题
            //参考;https://blog.csdn.net/hwt0101/article/details/80893212
            if (auditLogFilterOptions.IsEnabled && auditLogFilterOptions.Contributor.IsAuditFull)
                app.UseEnableBuffering();

            return app;
        }

        /// <summary>
        /// 设置WebApi默认主页
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseSgrDefaultFileNames(this IApplicationBuilder app, Action<DefaultFilesOptions>? configure = null)
        {
            DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions();

            defaultFilesOptions.DefaultFileNames.Clear();
            configure?.Invoke(defaultFilesOptions);

            app.UseDefaultFiles(defaultFilesOptions);
            app.UseStaticFiles();

            return app;
        }

        /// <summary>
        /// 启用请求缓冲
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseEnableBuffering(this IApplicationBuilder app)
        {
            var options = app.ApplicationServices.GetRequiredService<IEnableBufferingOptions>();

            if (!options.IsUsed)
            {
                app.Use(next => context =>
                {
                    context.Request.EnableBuffering();
                    return next(context);
                });

                options.IsUsed = true;
            }

            return app;
        }
    }
}